using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Security.Cryptography;
using System.Xml.Serialization;

using System.Collections.Generic;

//using Microsoft.SharePoint;


[System.ComponentModel.Description("LTI Tool Consumer Launch WebPart")]
public partial class LaunchPart : System.Web.UI.UserControl
{
    // Local variables
    private const string defaultText = "";
    private string _providerURL = "http://ltihost.wimba.com:8080/TITool-0.0.1/rest/launchws";
    private string _sharedSecret = "secret";
    private string _toolXml = string.Empty;
    private string _tpResourceId = "http://www.learngauge.com/ScormTest3.zip";
    //private launchRequest _launchMessage;


    //private SPWeb _website ;
    //private Microsoft.SharePoint.SPUser _spuser;
   
    private bool debug = false;

    // Properties
    [Browsable(true), Category("Tool Provider URL"), Description("Tool Provider URL")]
    public string ProviderURL
    {
        get { return _providerURL; }
        set { _providerURL = value; }
    }

    [Browsable(true), Category("Shared Secret"), Description("Tool Provider Shared Secret")]
    public string SharedSecret
    {
        get { return _sharedSecret; }
        set { _sharedSecret = value; }
    }

    [Browsable(true), Category("Tool XML"), Description("Tool Provider Parameterized XML")]
    public string ToolXml
    {
        get { return _toolXml; }
        set { _toolXml = value; }
    }

    [Browsable(true), Category("TP Resource ID"), Description("TP Resource ID")]
    public string TPResourceID
    {
        get { return _tpResourceId; }
        set { _tpResourceId = value; }
    }

    // Internal classes  ** NOT USED UNTIL CLOSER TO FINAL SPEC **
    public class IMSLTIURL
    {
        public string LaunchURL;
        public bool Success;
        public string Message;
        public string ResponseCode;

        public IMSLTIURL() { }
    }
    public class MessageData
    {
        public string RequestMessage;
        public string ResponseMessage;
        public String URL;
        public HttpStatusCode StatusCode;
        public MessageData() { }
    }


    public class launchRequest
    {
        public LaunchDefinition launchDefinition;
        public LaunchData launchData;
    }
    public class LaunchDefinition
    {
        public string UserToken; // Supplied by ToolConsumer
        public string ToolID; // Supplied by Tool Parameters
        public string ToolConsumerID;
        public string GroupID;
        public string DisplayTarget;
        public string ResourceID;
        public string PageID;
        public string CallbackURL;
        public string LaunchLink;
        public LaunchDefinition() { }
    }
    public class LaunchData
    {
        public LaunchUser user;
        public LaunchGroup group;
        public LaunchResource resource;
        public LaunchMembership membership;
        public LaunchData() { }
    }
    public class LaunchUser
    {
        public string firstName;
        public string lastName;
        public string fullName;
        public string email;
        public string systemRole;
        public string locale;
        public string sourceId;
        public LaunchUser() { } 
    }
    public class LaunchGroup
    {
        public string longDescription;
        public string shortDescription;
        public string locale;
        public string groupType;
        public string url;
        public string email;
        public string sourceId;
        public string available;
        public string enrollmentCount;
        public DateTime beginDate;
        public DateTime endDate;
        public GroupRelationship[] relationship;
        public LaunchGroup() { }
    }
    public class GroupRelationship
    {
        public string value;
    }
    public class LaunchResource
    {
        public string sourceId;
        public string toolId;
        public string title;
        public string subTitle;
        public string tpResourceId;
        public string tpAncillary;
        public LaunchResource() { }
    }
    public class GroupRole
    {
        public string value;
    }
    public class LaunchMembership
    {
        public string sourceId;
        public GroupRole[] groupRole;
        public LaunchMembership() { }
    }


    // Events

    // On Page load clean up label and iFrame
    protected void Page_Load(object sender, EventArgs e)
    {
        lblStatus.Text = string.Empty;
        ifrContent.Visible = false;

        //_website = SPContext.Current.Web;
        //_spuser = _website.CurrentUser;

        //_toolXml = GetToolXML();
    }

    // On launch click 
    protected void btnLaunch_Click(object sender, EventArgs e)
    {
        IMSLTIURL URL;
        //Response.Write(GetToolXML().Replace("\r\n", ""));

        // 
        // We have a decision to make:  If ToolXML is provided we use a web service SOAP 1.1. call
        // If Tool URL and Shared Secret are set then we use a REST call.
        //
        try
        {
            if (_toolXml != string.Empty)
            {
                // SOAP
                //CreateLaunchMessageSOAP();

                URL = GetLaunchURLSOAP(ParseToolXmlUrl(_toolXml));
                //URL = GetLaunchURLSOAP("http://www.scormtech.com/services/TPLaunchServiceSyncSoap.asmx");
                
            }
            else
            {
                // REST
                //CreateLaunchMessageREST();
                URL = GetLaunchURLREST(ProviderURL);
            }
            
            if (URL.Success)
            {
                LaunchURL(URL.LaunchURL);
            }
            else
            {

                // Parse Error
                XmlDocument x = new XmlDocument();
                x.Load(new StringReader(URL.Message));
                XmlNodeList xnl = x.SelectNodes("//ltierror/code");

                foreach (XmlNode xNode in xnl)
                {
                    lblStatus.Text += xNode.InnerText;
                }

            }
        }
        catch (Exception exception)
        {
            Response.Write("<pre>" + exception.Message.ToString() + "</pre>");
        }
    }


    // Functions


    // REST Functions

    // Get URL
    protected IMSLTIURL GetLaunchURLREST(string URL)
    {
        string responseCode = string.Empty;
        MessageData msg = new MessageData();
        IMSLTIURL URLStatus = new IMSLTIURL();
        msg.RequestMessage = GetLaunchMessageREST().ToString();
        msg.URL = URL;
        responseCode = SendMessageREST(msg);
        URLStatus.ResponseCode = responseCode;
        URLStatus.Message = msg.ResponseMessage;

        if (debug) Response.Write("<pre>" + Server.HtmlEncode(msg.ResponseMessage) + "</pre>");

        if (responseCode == "200")
        {
            XmlDocument x = new XmlDocument();
            x.Load(new StringReader(msg.ResponseMessage));
            XmlNodeList xnl = x.SelectNodes("//launchUrl");

            foreach (XmlNode xNode in xnl)
            {
                URLStatus.LaunchURL += xNode.InnerText;
            }
            if (debug) Response.Write("<pre>" + Server.HtmlEncode(msg.ResponseMessage) + "</pre>");
            URLStatus.Success = true;
        }
        else
        {
            URLStatus.Success = false;
        }

        if (debug) Response.Write("URL=" + URLStatus.LaunchURL);
        if (debug) Response.Write("<br />");
        return URLStatus;

    }

    // Send Message to Request Launch URL
    protected string SendMessageREST(MessageData msg)
    {
        HttpWebRequest request;
        HttpWebResponse response = null;
        StreamReader reader;
        Uri address;
        byte[] byteData;
        Stream postStream = null;
        string responseCode = string.Empty;

        string responseData = string.Empty;
        address = new Uri(msg.URL);

        //  Create the web request   
        request = (HttpWebRequest)WebRequest.Create(address);

        // Need authentication information
        System.Guid rand = System.Guid.NewGuid();  // Random number
        string randString = rand.ToString().Replace("-", ""); // (Remove - from GUID)
        string timeStamp = DateTime.UtcNow.ToString("s") + "Z";
        byte[] passwordDigest = EncryptString(randString + timeStamp + SharedSecret);

        if (debug) Response.Write("nonce + ts + secret=" + randString + timeStamp + SharedSecret);
        if (debug) Response.Write("<br />");
        if (debug) Response.Write("encrypted=" + new UTF8Encoding().GetString(EncryptString(randString + timeStamp + SharedSecret)));
        if (debug) Response.Write("<br />");
        if (debug) Response.Write("base64Encode=" + base64Encode(passwordDigest));
        if (debug) Response.Write("<br />");


        request.Headers.Add("Authorization", "WSSE profile=\"UsernameToken\"");
        request.Headers.Add("X-WSSE", "UsernameToken Username=\"ltitc\", PasswordDigest=\"" + base64Encode(passwordDigest) + "\",  Nonce=\"" + randString + "\", Created=\"" + timeStamp + "\"");

        //  Set type to POST   
        request.Method = "POST";
        // request.ContentType = "application/x-www-form-urlencoded";

        //  Create a byte array of the data we want to send   
        byteData = UTF8Encoding.UTF8.GetBytes(msg.RequestMessage);
        //  Set the content length in the request headers   
        request.ContentLength = byteData.Length;
        //  Write data   
        try
        {
            postStream = request.GetRequestStream();
            postStream.Write(byteData, 0, byteData.Length);
        }
        finally
        {
            if (!(postStream == null))
            {
                postStream.Close();
            }
            try
            {
                //  Get response   
                response = (HttpWebResponse)request.GetResponse();
                //  Get the response stream into a reader   
                reader = new StreamReader(response.GetResponseStream());
                //  Get reader into string to return
                msg.ResponseMessage = reader.ReadToEnd();
                if (response.StatusCode == HttpStatusCode.OK)
                    responseCode = "200";
                msg.StatusCode = response.StatusCode;

            }
            catch (WebException ex)
            {
                responseCode = ex.Status.ToString();


                if (ex.Status == WebExceptionStatus.ProtocolError)
                {
                    // ERROR
                    responseCode = "400";

                    reader = new StreamReader(ex.Response.GetResponseStream());
                    //  Console application output   
                    msg.ResponseMessage = reader.ReadToEnd();
                }
            }
            finally
            {
                if (!(response == null))
                {
                    response.Close();
                }
            }
        }

        return responseCode;
    }

    // Create the Launch Message from Sharepoint Data and Tool Data
    protected string CreateLaunchMessageREST()
    {
        string msg = GetRESTRequestXML();

        return msg;
    }

    // Returns a launch message -- NOT NEEDED RIGHT NOW
    protected string GetLaunchMessageREST()
    {
        /*
        // Create New Memorystream
        MemoryStream ms = new MemoryStream();
        // Create Serializer
        XmlSerializer xs = new XmlSerializer(_launchMessage.GetType());
        // Serialize object to memory
        xs.Serialize(ms, _launchMessage);
        ms.Position = 0;
        // return a string with XML
        using (StreamReader reader = new StreamReader(ms))
        {
            return reader.ReadToEnd();
        }
         * */
        return CreateLaunchMessageREST();
    }

    // SOAP functions

    // Get URL
    protected IMSLTIURL GetLaunchURLSOAP(string URL)
    {
        string responseCode = string.Empty;
        MessageData msg = new MessageData();
        IMSLTIURL URLStatus = new IMSLTIURL();
        msg.RequestMessage = GetLaunchMessageSOAP().ToString();
        msg.URL = URL;
        responseCode = SendMessageSOAP(msg);
        URLStatus.ResponseCode = responseCode;
        URLStatus.Message = msg.ResponseMessage;

        if (debug) Response.Write("<pre>" + Server.HtmlEncode(msg.ResponseMessage) + "</pre>");

        if (responseCode == "200")
        {
            //XmlDocument x = new XmlDocument();
            //x.Load(new StringReader());
            URLStatus.LaunchURL = getXmlValue(msg.ResponseMessage, "//*[local-name()='launchURL']");
            //XmlNodeList xnl = x.SelectNodes("/soap:Envelope/soap:Body/getLaunchURLResponse/launchURL");

            //foreach (XmlNode xNode in xnl)
            //{
             //   URLStatus.LaunchURL += xNode.InnerText;
            //}
            if (debug) Response.Write("<pre>" + Server.HtmlEncode(msg.ResponseMessage) + "</pre>");
            URLStatus.Success = true;
        }
        else
        {
            URLStatus.Success = false;
        }

        if (debug) Response.Write("URL=" + URLStatus.LaunchURL);
        if (debug) Response.Write("<br />");
        return URLStatus;

    }

    // Send Message to Request Launch URL
    protected string SendMessageSOAP(MessageData msg)
    {
        HttpWebRequest request;
        HttpWebResponse response = null;
        StreamReader reader;
        Uri address;
        byte[] byteData;
        Stream postStream = null;
        string responseCode = string.Empty;

        string responseData = string.Empty;
        address = new Uri(msg.URL);

        //  Create the web request   
        request = (HttpWebRequest)WebRequest.Create(address);

        request.ContentType = "text/xml; charset=utf-8";
        request.Headers.Add("SOAPAction", "\"http://www.imsglobal.org/soap/lti/lsv2p0/getLaunchURL\"");

        //  Set type to POST   
        request.Method = "POST";
        // request.ContentType = "application/x-www-form-urlencoded";

        //  Create a byte array of the data we want to send   
        byteData = UTF8Encoding.UTF8.GetBytes(msg.RequestMessage);
        //  Set the content length in the request headers   
        request.ContentLength = byteData.Length;
        //  Write data   
        try
        {
            postStream = request.GetRequestStream();
            postStream.Write(byteData, 0, byteData.Length);
        }
        finally
        {
            if (!(postStream == null))
            {
                postStream.Close();
            }
            try
            {
                //  Get response   
                response = (HttpWebResponse)request.GetResponse();
                //  Get the response stream into a reader   
                reader = new StreamReader(response.GetResponseStream());
                //  Get reader into string to return
                msg.ResponseMessage = reader.ReadToEnd();
                if (response.StatusCode == HttpStatusCode.OK)
                    responseCode = "200";
                msg.StatusCode = response.StatusCode;

            }
            catch (WebException ex)
            {
                responseCode = ex.Status.ToString();


                if (ex.Status == WebExceptionStatus.ProtocolError)
                {
                    // ERROR
                    responseCode = "400";

                    reader = new StreamReader(ex.Response.GetResponseStream());
                    //  Console application output   
                    msg.ResponseMessage = reader.ReadToEnd();
                }
            }
            finally
            {
                if (!(response == null))
                {
                    response.Close();
                }
            }
        }

        return responseCode;
    }
    
    // Create the Launch Message from Sharepoint Data and Tool Data
    protected string CreateLaunchMessageSOAP()
    {
        /*_launchMessage = new launchRequest();
        
        _launchMessage.launchDefinition = new LaunchDefinition();
        _launchMessage.launchDefinition.UserToken = _spuser.UserToken.ToString();

        _launchMessage.launchData = new LaunchData();
        _launchMessage.launchData.user = new LaunchUser();
        _launchMessage.launchData.user.firstName = _spuser.Name;
        _launchMessage.launchData.user.lastName = _spuser.Name;
        _launchMessage.launchData.user.fullName = _spuser.Name;
        _launchMessage.launchData.user.email = _spuser.Email;
        _launchMessage.launchData.user.locale = _spuser.RegionalSettings.Locales[0].DisplayName;
        
        _launchMessage.launchData.user.systemRole = string.Empty;

        _launchMessage.launchData.resource = new LaunchResource();
        _launchMessage.launchData.group = new LaunchGroup();
        _launchMessage.launchData.membership = new LaunchMembership();
         * */

        string msg = GetSOAPRequestXML();
        msg = msg.Replace( "@tPResourceID@" , _tpResourceId);
        return msg;
    }

    // Returns a launch message
    protected string GetLaunchMessageSOAP()
    {
        /*
        // Create New Memorystream
        MemoryStream ms = new MemoryStream();
        // Create Serializer
        XmlSerializer xs = new XmlSerializer(_launchMessage.GetType());
        // Serialize object to memory
        xs.Serialize(ms, _launchMessage);
        ms.Position = 0;
        // return a string with XML
        using (StreamReader reader = new StreamReader(ms))
        {
            return reader.ReadToEnd();
        }
         * */
        return CreateLaunchMessageSOAP();
    }

    // If tool xml has been supplied parse it
    protected string ParseToolXmlUrl(string toolXml)
    {
        // Extract Launch URL
        return getXmlValue(toolXml, "//*[local-name()='serviceLaunch']/*[local-name()='url']"); ///launchRequirements/launchType/serviceLaunch/url

    }
    
    protected void LaunchURL(string URL)
    {
        ifrContent.InnerHtml = URL;
        ifrContent.Attributes["src"] = URL;
        ifrContent.Visible = true;
        if (debug) Response.Write("URL=" + URL);
        if (debug) Response.Write("<br />");
    }


    // Library Functions
    protected byte[] EncryptString(string instr)
    {
        UTF8Encoding encoding = new UTF8Encoding();
        //UnicodeEncoding encoding = new UnicodeEncoding();
        byte[] hashBytes = encoding.GetBytes(instr);

        // compute SHA-1 hash.
        SHA1 sha1 = new SHA1CryptoServiceProvider();
        byte[] cryptstr = sha1.ComputeHash(hashBytes);


        return cryptstr;
    }
    protected string base64Encode(string data)
    {
        try
        {
            byte[] encData_byte = new byte[data.Length];
            encData_byte = System.Text.Encoding.UTF8.GetBytes(data);
            string encodedData = Convert.ToBase64String(encData_byte);
            return encodedData;
        }
        catch (Exception e)
        {
            throw new Exception("Error in base64Encode" + e.Message);
        }
    }
    protected string base64Encode(byte[] data)
    {
        try
        {

            string encodedData = Convert.ToBase64String(data);
            return encodedData;
        }
        catch (Exception e)
        {
            throw new Exception("Error in base64Encode" + e.Message);
        }
    }

    private string getXmlValue(string XmlMessage, string XmlNode)
    {

        string XmlValue = string.Empty;
        // Parse Error

        
        XmlDocument x = new XmlDocument();

        x.Load(new StringReader(XmlMessage));


        XmlNodeList xnl = x.SelectNodes(XmlNode);
        //Response.Write(x.FirstChild.InnerText);
        

        foreach (XmlNode xNode in xnl)
        {
            XmlValue += xNode.InnerText;
        }
        return XmlValue;

    }

    private string setXmlValue(string XmlMessage, string XmlNode, string XmlValue)
    {
        XmlDocument x = new XmlDocument();
        x.Load(new StringReader(XmlMessage));
        XmlNodeList xnl = x.SelectNodes(XmlNode);

        foreach (XmlNode xNode in xnl)
        {
            xNode.InnerText = XmlValue;
        }
        StringWriter sw = new StringWriter();
        XmlTextWriter xw = new XmlTextWriter(sw);
        x.WriteTo(xw);
        return sw.ToString();


    }

    //
    // We define XML here so it can be easily modified later 
    //
    private string GetSOAPRequestXML()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n");
        sb.Append("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n");
        sb.Append("  <soap:Header>\r\n");
        sb.Append("    <imsx_syncRequestHeaderInfo xmlns=\"http://www.imsglobal.org/services/lti/ls2p0/wsdl11/sync/imsls_v2p0\">\r\n");
        sb.Append("      <imsx_version>string</imsx_version>\r\n");
        sb.Append("      <imsx_messageIdentifier>string</imsx_messageIdentifier>\r\n");
        sb.Append("    </imsx_syncRequestHeaderInfo>\r\n");
        sb.Append("  </soap:Header>\r\n");
        sb.Append("  <soap:Body>\r\n");
        sb.Append("    <getLaunchURLRequest xmlns=\"http://www.imsglobal.org/services/lti/ls2p0/wsdl11/sync/imsls_v2p0\">\r\n");
        sb.Append("      <launchRequest>\r\n");
        sb.Append("        <launchDefiniton>\r\n");
        sb.Append("          <userToken>string</userToken>\r\n");
        sb.Append("          <toolId>string</toolId>\r\n");
        sb.Append("          <toolConsumerId>string</toolConsumerId>\r\n");
        sb.Append("          <groupId>string</groupId>\r\n");
        sb.Append("          <displayTarget>IFrame</displayTarget>\r\n");
        sb.Append("          <resourceId>string</resourceId>\r\n");
        sb.Append("          <pageId>string</pageId>\r\n");
        sb.Append("          <callbackURL>string</callbackURL>\r\n");
        sb.Append("          <launchLink>string</launchLink>\r\n");
        sb.Append("          <systemRole>User</systemRole>\r\n");
        //sb.Append("          <systemRole>SysAdmin or SysSupport or Creator or AccountAdmin or User or Administrator or None</systemRole>\r\n");
        sb.Append("          <groupRoles>\r\n");
        sb.Append("            <groupRole>Learner</groupRole>\r\n");
        //sb.Append("            <groupRole>Learner or Instructor or ContentDeveloper or Member or Manager or Mentor or Administrator or TeachingAssistant</groupRole>\r\n");
        sb.Append("          </groupRoles>\r\n");
        sb.Append("        </launchDefiniton>\r\n");
        sb.Append("        <launchData>\r\n");
        sb.Append("          <user>\r\n");
        sb.Append("            <firstName>string</firstName>\r\n");
        sb.Append("            <lastName>string</lastName>\r\n");
        sb.Append("            <fullName>string</fullName>\r\n");
        sb.Append("            <email>string</email>\r\n");
        sb.Append("            <systemRole>User</systemRole>\r\n");
        //sb.Append("            <systemRole>SysAdmin or SysSupport or Creator or AccountAdmin or User or Administrator or None</systemRole>\r\n");
        sb.Append("            <locale>string</locale>\r\n");
        sb.Append("            <sourceId>string</sourceId>\r\n");
        sb.Append("          </user>\r\n");
        sb.Append("          <group>\r\n");
        sb.Append("            <longDescription>string</longDescription>\r\n");
        sb.Append("            <shortDescription>string</shortDescription>\r\n");
        sb.Append("            <locale>string</locale>\r\n");
        sb.Append("            <groupType>course</groupType>\r\n");
        sb.Append("            <url>string</url>\r\n");
        sb.Append("            <email>string</email>\r\n");
        sb.Append("            <sourceId>string</sourceId>\r\n");
        sb.Append("            <available>true</available>\r\n");
        sb.Append("            <enrollmentCount>1</enrollmentCount>\r\n");
        //sb.Append("            <beginDate>2008-01-01T12:00:00Z</beginDate>\r\n");
        //sb.Append("            <endDate>2008-12-01T12:00:00Z</endDate>\r\n");
        sb.Append("            <relationships>parent</relationships>\r\n");
        //sb.Append("            <relationships>parent or child or parentChild</relationships>\r\n");
        sb.Append("          </group>\r\n");
        sb.Append("          <resource>\r\n");
        sb.Append("            <sourceId>string</sourceId>\r\n");
        sb.Append("            <toolId>string</toolId>\r\n");
        sb.Append("            <title>string</title>\r\n");
        sb.Append("            <subTitle>string</subTitle>\r\n");
        sb.Append("            <tPResourceId>@tPResourceID@</tPResourceId>\r\n");
        sb.Append("            <tPAncillary>string</tPAncillary>\r\n");
        sb.Append("          </resource>\r\n");
        sb.Append("          <membership>\r\n");
        sb.Append("            <sourceId>string</sourceId>\r\n");
        sb.Append("            <roles>Learner</roles>\r\n");
        //sb.Append("            <roles>Learner or Instructor or ContentDeveloper or Member or Manager or Mentor or Administrator or TeachingAssistant</roles>\r\n");
        sb.Append("          </membership>\r\n");
        sb.Append("        </launchData>\r\n");
        sb.Append("      </launchRequest>\r\n");
        sb.Append("    </getLaunchURLRequest>\r\n");
        sb.Append("  </soap:Body>\r\n");
        sb.Append("</soap:Envelope>");
        return sb.ToString();
    }

    private string GetRESTRequestXML()
    {
        StringBuilder sb = new StringBuilder();    
        // Launch Message
        sb.Append("<launchRequest>\r\n");
        sb.Append("  <launchDefinition>\r\n");
        sb.Append("      <userToken>userToken</userToken>\r\n");
        sb.Append("      <toolId>wimbaclassroomlti</toolId>\r\n");
        sb.Append("      <toolConsumerId>moodle_0a1b_2</toolConsumerId>\r\n");
        sb.Append("      <groupId>contextId</groupId>\r\n");
        sb.Append("      <displayTarget>IFrame</displayTarget>\r\n");
        sb.Append("      <resourceId>resourceId</resourceId>\r\n");
        sb.Append("      <pageId>2</pageId>\r\n");
        sb.Append("      <callbackUrl>callbackURL</callbackUrl>\r\n");
        sb.Append("      <launchLink>groupview</launchLink>\r\n");
        sb.Append("  </launchDefinition>\r\n");
        sb.Append("  <launchData>\r\n");
        sb.Append("      <user>\r\n");
        sb.Append("          <firstName>firstname</firstName>\r\n");
        sb.Append("          <lastName>lastName</lastName>\r\n");
        sb.Append("          <fullName>fullName</fullName>\r\n");
        sb.Append("          <email>email</email>\r\n");
        sb.Append("          <systemRole>Administrator</systemRole>\r\n");
        sb.Append("          <locale>locale</locale>\r\n");
        sb.Append("          <sourceId>sourceId</sourceId>\r\n");
        sb.Append("      </user>\r\n");
        sb.Append("      <group>\r\n");
        sb.Append("          <longDescription>longdescription</longDescription>\r\n");
        sb.Append("          <shortDescription>shortdescription</shortDescription>\r\n");
        sb.Append("          <locale>locale</locale>\r\n");
        sb.Append("          <groupType>course</groupType>\r\n");
        sb.Append("          <url>url</url>\r\n");
        sb.Append("          <email>email</email>\r\n");
        sb.Append("          <sourceId>sourceId</sourceId>\r\n");
        sb.Append("          <available>true</available>\r\n");
        sb.Append("          <enrollmentCount>16</enrollmentCount>\r\n");
        sb.Append("          <beginDate>2008-04-22T18:37:26.544Z</beginDate>\r\n");
        sb.Append("          <endDate>2008-04-22T18:37:26.544Z</endDate>\r\n");
        sb.Append("          <relationships>\r\n");
        sb.Append("              <relationship>\r\n");
        sb.Append("                  <value>child</value>\r\n");
        sb.Append("              </relationship>\r\n");
        sb.Append("          </relationships>\r\n");
        sb.Append("      </group>\r\n");
        sb.Append("      <resource>\r\n");
        sb.Append("          <sourceId>sourceId</sourceId>\r\n");
        sb.Append("          <toolId>tooldId</toolId>\r\n");
        sb.Append("          <title>title</title>\r\n");
        sb.Append("          <subTitle>subTitle</subTitle>\r\n");
        sb.Append("          <tpResourceId>TPResId</tpResourceId>\r\n");
        sb.Append("          <tpAncillary>TPAncillary</tpAncillary>\r\n");
        sb.Append("      </resource>\r\n");
        sb.Append("      <membership>\r\n");
        sb.Append("          <sourceId>sourceId</sourceId>\r\n");
        sb.Append("          <groupRoles>\r\n");
        sb.Append("              <groupRole>\r\n");
        sb.Append("                  <value>Instructor</value>\r\n");
        sb.Append("              </groupRole>\r\n");
        sb.Append("          </groupRoles>\r\n");
        sb.Append("      </membership>\r\n");
        sb.Append("  </launchData>\r\n");
        sb.Append("</launchRequest>\r\n");

        return sb.ToString();
    }

    private string GetToolXML()
    {
        StringBuilder sb = new StringBuilder();    
        sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?> \r\n");
        sb.Append("<ToolProfile \r\n");
        sb.Append("   xmlns=\"http://www.imsglobal.org/xsd/imsltitp_v2p0\"\r\n");
        sb.Append("   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n");
        sb.Append("   xsi:schemaLocation=\"http://www.imsglobal.org/xsd/imsltitp_v2p0/imsltitp_v2p0.xsd\">\r\n");
        sb.Append("  \r\n");
        sb.Append("  <id>icodeon_scorm_player</id>\r\n");
        sb.Append("  <name>Icodeon SCORM Player</name>\r\n");
        sb.Append("  <description>SCORM 2004 SCORM Run Time Environment</description>\r\n");
        sb.Append("  <locale>en_utf8</locale>\r\n");
        sb.Append("  <imageURL>http://www.icodeon.com/images/icodeon_icon_16_16</imageURL>\r\n");
        sb.Append("  <version>1.0.0</version>\r\n");
        sb.Append("  <ltiVersion>2.0</ltiVersion>\r\n");
        sb.Append("  \r\n");
        sb.Append("  <vendor>\r\n");
        sb.Append("    <id>icodeon</id>\r\n");
        sb.Append("    <name>Icodeon</name>\r\n");
        sb.Append("    <url>http://www.icodeon.com/</url>\r\n");
        sb.Append("    <description>The Icodeon is based in Cambridge, UK</description>\r\n");
        sb.Append("  </vendor>\r\n");
        sb.Append("  \r\n");
        sb.Append("  <launchRequirements>\r\n");
        sb.Append("    <launchType>\r\n");
        sb.Append("      <serviceLaunch>\r\n");
        sb.Append("        <url>http://www.scormtech.com/services/TPLaunchServiceSyncSoap.asmx</url>\r\n");
        sb.Append("        <includeLaunchdata>true</includeLaunchdata>\r\n");
        sb.Append("      </serviceLaunch>\r\n");
        sb.Append("    </launchType>\r\n");
        sb.Append("    <requiredServices>\r\n");
        sb.Append("      <service>\r\n");
        sb.Append("        <name>TCCallbackService</name>\r\n");
        sb.Append("        <version>1.0</version>\r\n");
        sb.Append("        <description>Service returning the callback URL depending on the target type</description>\r\n");
        sb.Append("      </service>\r\n");
        sb.Append("      <service>\r\n");
        sb.Append("        <name>TCResourceService</name>\r\n");
        sb.Append("        <version>1.0</version>\r\n");
        sb.Append("        <description>Service providing interfaces for CRUD operations within the Tool Consumer</description>\r\n");
        sb.Append("      </service>\r\n");
        sb.Append("    </requiredServices>\r\n");
        sb.Append("  </launchRequirements>\r\n");
        sb.Append("  \r\n");
        sb.Append("  <launchLinks>\r\n");
        sb.Append("    <launchLink>\r\n");
        sb.Append("      <name>Icodeon Customer Support</name>\r\n");
        sb.Append("      <description>Link to Icodeon Customer Support</description>\r\n");
        sb.Append("      <type>groupview</type>\r\n");
        sb.Append("      <displayTarget>IFrame</displayTarget>\r\n");
        sb.Append("    </launchLink>\r\n");
        sb.Append("    <launchLink>\r\n");
        sb.Append("      <name>Icodeon Labs</name>\r\n");
        sb.Append("      <description>Link to Icodeon Collaboration Space</description>\r\n");
        sb.Append("      <type>resourceview</type>\r\n");
        sb.Append("      <displayTarget>iframe</displayTarget>\r\n");
        sb.Append("    </launchLink>\r\n");
        sb.Append("    \r\n");
        sb.Append("  </launchLinks>\r\n");
        sb.Append("  \r\n");
        sb.Append("  <servicesOffered>\r\n");
        sb.Append("    <service>\r\n");
        sb.Append("      <name>TPLaunchService</name>\r\n");
        sb.Append("      <version>1.0</version>\r\n");
        sb.Append("      <description>Service providing the launch URLs to the Tool Consumer</description>\r\n");
        sb.Append("      <url>http://www.scormtech.com/services/TPLaunchServiceSyncSoap.asmx</url>\r\n");
        sb.Append("    </service>\r\n");
        sb.Append("  </servicesOffered>\r\n");
        sb.Append("  \r\n");
        sb.Append("</ToolProfile>\r\n");
        return sb.ToString();
    }



}

/*
 * SOAP Request
 * 

POST /services/TPLaunchServiceSyncSoap.asmx HTTP/1.1
Host: www.scormtech.com
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.imsglobal.org/soap/lti/lsv2p0/getLaunchURL"


<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <imsx_syncRequestHeaderInfo xmlns="http://www.imsglobal.org/services/lti/ls2p0/wsdl11/sync/imsls_v2p0">
      <imsx_version>string</imsx_version>
      <imsx_messageIdentifier>string</imsx_messageIdentifier>
    </imsx_syncRequestHeaderInfo>
  </soap:Header>
  <soap:Body>
    <getLaunchURLRequest xmlns="http://www.imsglobal.org/services/lti/ls2p0/wsdl11/sync/imsls_v2p0">
      <launchRequest>
        <launchDefiniton>
          <userToken>string</userToken>
          <toolId>string</toolId>
          <toolConsumerId>string</toolConsumerId>
          <groupId>string</groupId>
          <displayTarget>NewWindow or IFrame</displayTarget>
          <resourceId>string</resourceId>
          <pageId>string</pageId>
          <callbackURL>string</callbackURL>
          <launchLink>string</launchLink>
          <systemRole>SysAdmin or SysSupport or Creator or AccountAdmin or User or Administrator or None</systemRole>
          <groupRoles>
            <groupRole>Learner or Instructor or ContentDeveloper or Member or Manager or Mentor or Administrator or TeachingAssistant</groupRole>
            <groupRole>Learner or Instructor or ContentDeveloper or Member or Manager or Mentor or Administrator or TeachingAssistant</groupRole>
          </groupRoles>
        </launchDefiniton>
        <launchData>
          <user>
            <firstName>string</firstName>
            <lastName>string</lastName>
            <fullName>string</fullName>
            <email>string</email>
            <systemRole>SysAdmin or SysSupport or Creator or AccountAdmin or User or Administrator or None</systemRole>
            <locale>string</locale>
            <sourceId>string</sourceId>
          </user>
          <group>
            <longDescription>string</longDescription>
            <shortDescription>string</shortDescription>
            <locale>string</locale>
            <groupType>course</groupType>
            <url>string</url>
            <email>string</email>
            <sourceId>string</sourceId>
            <available>boolean</available>
            <enrollmentCount>integer</enrollmentCount>
            <beginDate>date</beginDate>
            <endDate>date</endDate>
            <relationships>parent or child or parentChild</relationships>
            <relationships>parent or child or parentChild</relationships>
          </group>
          <resource>
            <sourceId>string</sourceId>
            <toolId>string</toolId>
            <title>string</title>
            <subTitle>string</subTitle>
            <tPResourceId>string</tPResourceId>
            <tPAncillary>string</tPAncillary>
          </resource>
          <membership>
            <sourceId>string</sourceId>
            <roles>Learner or Instructor or ContentDeveloper or Member or Manager or Mentor or Administrator or TeachingAssistant</roles>
            <roles>Learner or Instructor or ContentDeveloper or Member or Manager or Mentor or Administrator or TeachingAssistant</roles>
          </membership>
        </launchData>
      </launchRequest>
    </getLaunchURLRequest>
  </soap:Body>
</soap:Envelope>
 * 
 * 
 * 
 * 
 * SOAP Response
 * 
 * 

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <imsx_syncResponseHeaderInfo xmlns="http://www.imsglobal.org/services/lti/ls2p0/wsdl11/sync/imsls_v2p0">
      <imsx_version>string</imsx_version>
      <imsx_messageIdentifier>string</imsx_messageIdentifier>
      <imsx_statusInfo>
        <imsx_codeMajor>success or processing or failure or unsupported</imsx_codeMajor>
        <imsx_severity>status or warning or error</imsx_severity>
        <imsx_messageRefIdentifier>string</imsx_messageRefIdentifier>
        <imsx_operationRefIdentifier>string</imsx_operationRefIdentifier>
        <imsx_operationRefIdentifier>string</imsx_operationRefIdentifier>
        <imsx_description>string</imsx_description>
        <imsx_codeMinor>
          <imsx_codeMinorField>
            <imsx_codeMinorFieldName>string</imsx_codeMinorFieldName>
            <imsx_codeMinorFieldValue>fullsuccess or idalloc or overflowfail or idallocinusefail or invaliddata or incompletedata or partialdatastorage or unknownobject or deletefailure or targetreadfailure or savepointerror or unknownquery or unknownvocab or targetisbusy or unauthorizedrequest or linkfailure or unsupported</imsx_codeMinorFieldValue>
          </imsx_codeMinorField>
          <imsx_codeMinorField>
            <imsx_codeMinorFieldName>string</imsx_codeMinorFieldName>
            <imsx_codeMinorFieldValue>fullsuccess or idalloc or overflowfail or idallocinusefail or invaliddata or incompletedata or partialdatastorage or unknownobject or deletefailure or targetreadfailure or savepointerror or unknownquery or unknownvocab or targetisbusy or unauthorizedrequest or linkfailure or unsupported</imsx_codeMinorFieldValue>
          </imsx_codeMinorField>
        </imsx_codeMinor>
      </imsx_statusInfo>
    </imsx_syncResponseHeaderInfo>
  </soap:Header>
  <soap:Body>
    <getLaunchURLResponse xmlns="http://www.imsglobal.org/services/lti/ls2p0/wsdl11/sync/imsls_v2p0">
      <launchURL>string</launchURL>
    </getLaunchURLResponse>
  </soap:Body>
</soap:Envelope>
 * 
 * TOOL XML Config
 * 
 * 
 * 
 * 
<?xml version="1.0" encoding="UTF-8"?>
<ToolProfile
xmlns="http://www.imsglobal.org/xsd/imsltitp_v2p0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.imsglobal.org/xsd/imsltitp_v2p0/imsltitp_v2p0.xsd">

 <id>icodeon_scorm_player</id>
 <name>Icodeon SCORM Player</name>
 <description>SCORM 2004 SCORM Run Time Environment</description>
 <locale>en_utf8</locale>
 <imageURL>http://www.icodeon.com/images/icodeon_icon_16_16</imageURL>
 <version>1.0.0</version>
 <ltiVersion>2.0</ltiVersion>

 <vendor>
   <id>icodeon</id>
   <name>Icodeon</name>
   <url>http://www.icodeon.com/</url>
   <description>The Icodeon is based in Cambridge, UK</description>
 </vendor>

 <launchRequirements>
   <launchType>
     <serviceLaunch>
       <url>http://www.scormtech.com/services/TPLaunchServiceSyncSoap.asmx</url>
       <includeLaunchdata>true</includeLaunchdata>
     </serviceLaunch>
   </launchType>
   <requiredServices>
     <service>
       <name>TCCallbackService</name>
       <version>1.0</version>
       <description>Service returning the callback URL depending on the target type</description>
     </service>
     <service>
       <name>TCResourceService</name>
       <version>1.0</version>
       <description>Service providing interfaces for CRUD operations within the Tool Consumer</description>
     </service>
   </requiredServices>
 </launchRequirements>

 <launchLinks>
   <launchLink>
     <name>Icodeon Customer Support</name>
     <description>Link to Icodeon Customer Support</description>
     <type>groupview</type>
     <displayTarget>iframe</displayTarget>
   </launchLink>
   <launchLink>
     <name>Icodeon Labs</name>
     <description>Link to Icodeon Collaboration Space</description>
     <type>resourceview</type>
     <displayTarget>iframe</displayTarget>
   </launchLink>

 </launchLinks>

 <servicesOffered>
   <service>
     <name>TPLaunchService</name>
     <version>1.0</version>
     <description>Service providing the launch URLs to the Tool Consumer</description>
     <url>http://www.scormtech.com/services/TPLaunchServiceSyncSoap.asmx</url>
   </service>
 </servicesOffered>

</ToolProfile>
 * 
 * 
 * 
 * Flattened TOOL XML
 * 
 * 
 * <?xml version="1.0" encoding="UTF-8"?> <ToolProfile    xmlns="http://www.imsglobal.org/xsd/imsltitp_v2p0"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://www.imsglobal.org/xsd/imsltitp_v2p0/imsltitp_v2p0.xsd">    <id>icodeon_scorm_player</id>  <name>Icodeon SCORM Player</name>  <description>SCORM 2004 SCORM Run Time Environment</description>  <locale>en_utf8</locale>  <imageURL>http://www.icodeon.com/images/icodeon_icon_16_16</imageURL>  <version>1.0.0</version>  <ltiVersion>2.0</ltiVersion>    <vendor>    <id>icodeon</id>    <name>Icodeon</name>    <url>http://www.icodeon.com/</url>    <description>The Icodeon is based in Cambridge, UK</description>  </vendor>    <launchRequirements>    <launchType>      <serviceLaunch>        <url>http://www.scormtech.com/services/TPLaunchServiceSyncSoap.asmx</url>        <includeLaunchdata>true</includeLaunchdata>      </serviceLaunch>    </launchType>    <requiredServices>      <service>        <name>TCCallbackService</name>        <version>1.0</version>        <description>Service returning the callback URL depending on the target type</description>      </service>      <service>        <name>TCResourceService</name>        <version>1.0</version>        <description>Service providing interfaces for CRUD operations within the Tool Consumer</description>      </service>    </requiredServices>  </launchRequirements>    <launchLinks>    <launchLink>      <name>Icodeon Customer Support</name>      <description>Link to Icodeon Customer Support</description>      <type>groupview</type>      <displayTarget>IFrame</displayTarget>    </launchLink>    <launchLink>      <name>Icodeon Labs</name>      <description>Link to Icodeon Collaboration Space</description>      <type>resourceview</type>      <displayTarget>iframe</displayTarget>    </launchLink>      </launchLinks>    <servicesOffered>    <service>      <name>TPLaunchService</name>      <version>1.0</version>      <description>Service providing the launch URLs to the Tool Consumer</description>      <url>http://www.scormtech.com/services/TPLaunchServiceSyncSoap.asmx</url>    </service>  </servicesOffered>  </ToolProfile>

*/